#include "../../config.h"

#include <glibmm/i18n.h>

#include "../icon.h"
#include "p_icon.h"

namespace gpyp {
namespace pref {

//========================
// IconView
void IconView::init() {
  columnrecord_.add(column_name_);
  columnrecord_.add(column_pixbuf_);
  liststore_ = Gtk::ListStore::create(columnrecord_);

  set_model(liststore_);
  //set_text_column(column_name_);
  set_pixbuf_column(column_pixbuf_);
  //set_item_width(72);
}

void IconView::reset_from_theme() {
  liststore_->clear();

  /* Gtk::IconTheme::list_icons()は2.10以降 */
  GList *icons = gtk_icon_theme_list_icons(theme_->gobj(), NULL);
  for(GList *icon = icons; icon; icon = icon->next) {
    Gtk::TreeIter treeiter  = liststore_->append();
    Glib::ustring icon_name = ((const gchar *)icon->data);
    treeiter->set_value(column_name_,   icon_name);
    treeiter->set_value(column_pixbuf_,
                        theme_->load_icon(icon_name, 16,
                                          (Gtk::IconLookupFlags)0));
    g_free(icon->data);
  }
  g_list_free(icons);
}

bool IconView::get_selected(Glib::ustring &name) const {
  if (get_selected_items().size()) {
    name = liststore_->get_iter(*get_selected_items().begin())
      ->get_value(column_name_);
    return true;
  }
  return false;
}
bool IconView::set_selected(const Glib::ustring name) {
  if (name.empty()) {
    unselect_all();
  } else {
    Gtk::TreeNodeChildren children = liststore_->children();
    for(Gtk::TreeIter iter = children.begin();
        iter != children.end(); ++iter) {
      if (iter->get_value(column_name_) == name) {
        select_path(liststore_->get_path(iter));
        return true;
      }
    }
  }
  return false;
}

IconView::IconView() {
  init();
  GSList *stock_ids = gtk_stock_list_ids();
  for(GSList *stock_id = stock_ids; stock_id; stock_id = stock_id->next) {
    if (IconManager::is_special_icon((const gchar *)stock_id->data)) continue;
    GdkPixbuf *pixbuf =
      gtk_widget_render_icon(GTK_WIDGET(gobj()),
                             (const gchar *)stock_id->data,
                             GTK_ICON_SIZE_MENU,
                             NULL);
    if (pixbuf) {
      Glib::ustring name = (const gchar *)stock_id->data;
      Gtk::TreeIter treeiter = liststore_->append();
      treeiter->set_value(column_name_,   name);
      treeiter->set_value(column_pixbuf_, Glib::wrap(pixbuf));
    }
  }
  g_slist_foreach(stock_ids, (GFunc)g_free, NULL);
  g_slist_free(stock_ids);
}
IconView::IconView(const char *const *icon_names) {
  init();
  for(const char *const *name = icon_names; *name; ++name) {
    Glib::ustring n(*name);
    Gtk::TreeIter treeiter = liststore_->append();
    treeiter->set_value(column_name_, n);
    treeiter->set_value(column_pixbuf_,
                        IconManager::load_icon(n, IconManager::ICON_SIZE_16));
  }
}
IconView::IconView(Glib::RefPtr<Gtk::IconTheme> theme) :
  theme_(theme)
{
  init();
  reset_from_theme();
  conn_theme_changed_ = theme_->signal_changed()
    .connect(sigc::mem_fun(*this, &IconView::reset_from_theme));
}
IconView::~IconView() {
#if (GTK_VERSION_MAJOR == 2) && (GTK_VERSION_MINOR == 16)
  // クラッシュ回避
  unset_model();
#endif
  conn_theme_changed_.disconnect();
}

//========================
// IconSelector::OtherPage
Glib::RefPtr<Gdk::Pixbuf> IconSelector::OtherPage::get_invalid_icon() {
  static Glib::RefPtr<Gdk::Pixbuf> refpb;
  if (!refpb) {
    gint w, h;
    gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);

    GdkPixmap *pm = gdk_pixmap_new(NULL, w, h, 24);
    cairo_t   *cr = gdk_cairo_create(GDK_DRAWABLE(pm));
    int        s  = MIN(w, h);

    cairo_rectangle(cr, 0, 0, w, h);
    cairo_set_source_rgb(cr, 1, 1, 1);
    cairo_fill(cr);

    //cairo_save(cr);
    cairo_translate(cr, w / 2.0, h / 2.0);
    cairo_scale(cr, s * 0.4, s * 0.4);
    cairo_set_line_width(cr, 0.4);
    cairo_set_source_rgb(cr, 0.85, 0.85, 0.85);
    cairo_arc(cr, 0, 0, 1, 0, 2 * M_PI);
    cairo_stroke(cr);
    cairo_new_path(cr);
    double p = sqrt(0.5);
    cairo_move_to(cr,  p, -p);
    cairo_line_to(cr, -p,  p);
    cairo_stroke(cr);
    //cairo_restore(cr);
    cairo_destroy(cr);

    GdkPixbuf *pb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, w, h);
    gdk_pixbuf_get_from_drawable(pb, GDK_DRAWABLE(pm), NULL,
                                 0, 0, 0, 0, w, h);
    g_object_unref(pm);
    refpb = Glib::wrap(pb);
  }
  return refpb;
}

void IconSelector::OtherPage::file_dialog_on_response(int response_id) {
  if (response_id == Gtk::RESPONSE_OK) {
    icon_name_.set_text(file_dialog_->get_filename());
  }
}

void IconSelector::OtherPage::icon_name_on_changed() {
  Glib::RefPtr<Gdk::Pixbuf> pb = IconManager::load_icon(icon_name_.get_text(), GTK_ICON_SIZE_MENU);
  if (!pb) pb = get_invalid_icon();
  icon_.set(pb);
}
void IconSelector::OtherPage::icon_open_on_clicked() {
  if (!file_dialog_) {
    file_dialog_.reset(new Gtk::FileChooserDialog(parent_, _("Open"), Gtk::FILE_CHOOSER_ACTION_OPEN));

    Gtk::FileFilter filter;
    filter.add_pattern("*.png");
    filter.add_pattern("*.xpm");
    filter.set_name(_("Supported image file"));
    file_dialog_->set_filter(filter);
    file_dialog_->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
    file_dialog_->add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
  }
  file_dialog_->set_filename(icon_name_.get_text());
  file_dialog_->show();
}

IconSelector::OtherPage::OtherPage(Gtk::Window &parent) :
  Gtk::VBox (false, 2),
  parent_   (parent),
  icon_open_(Gtk::Stock::OPEN),
  note_     (Glib::ustring(), Gtk::ALIGN_LEFT)
{
  note_.set_label(_("Note: You can use icon-name in current icon theme."));

  Gtk::HBox *h1 = Gtk::manage(new Gtk::HBox(false, 2));
  h1->pack_start(icon_,      false, false);
  h1->pack_start(icon_name_);
  h1->pack_start(icon_open_, false, false);
  pack_start(*h1,   false, false);
  pack_start(note_, false, false);

  file_dialog_.signal_response().connect(sigc::mem_fun(*this, &OtherPage::file_dialog_on_response));

  icon_name_on_changed();
  icon_name_.signal_changed()
    .connect(sigc::mem_fun(*this, &OtherPage::icon_name_on_changed));
  icon_open_.signal_clicked()
    .connect(sigc::mem_fun(*this, &OtherPage::icon_open_on_clicked));
}

//========================
// IconSelector
void IconSelector::set_icon_name(const Glib::ustring &name) {
  for(PageList::reverse_iterator iter = pages_.rbegin();
      iter != pages_.rend(); ++iter) {
    if ((*iter)->set_selected(name)) {
      set_current_page(page_num(*dynamic_cast<Gtk::Widget *>(*iter)));
    }
  }
}
Glib::ustring IconSelector::get_icon_name() const {
  Glib::ustring res;
  pages_[get_current_page()]->get_selected(res);
  return res;
}

void IconSelector::add() {
  Gtk::FileChooserDialog dialog(parent_, _("Open icon file"));
  dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
  if (dialog.run() == Gtk::RESPONSE_OK) {
    try {
      std::string name = Glib::path_get_basename(dialog.get_filename());
      std::string::size_type pos = name.rfind('.');
      if (pos != std::string::npos) name.erase(pos);
      IconManager::add_icon_file(dialog.get_filename());
      set_current_page(page_num(user_));
      user_.set_selected(name);
    } catch(const Glib::Exception &ex) {
      log::err << ex.what() << log::endl;
    }
  }
}
void IconSelector::remove() {
  if (!IconManager::remove_icon_file(get_icon_name())) {
    ErrorDialog(parent_, _("Failed to remove icon")).run();
  }
}

IconSelector::IconSelector(Gtk::Window &parent) :
  parent_ (parent),
  builtin_(IconManager::BUILTIN_ICON_LIST),
  user_   (IconManager::get_icontheme_user()),
  other_  (parent)
{
  append_page(builtin_, _("Built in"));
  append_page(user_,    _("User"));
  append_page(stock_,   _("Stock"));
  append_page(other_,   _("Other"));
  show_all();
}

//========================
// IconSelectorDialog
void IconSelectorDialog::on_realize() {
  Gtk::Dialog::on_realize();
  set_icon_name(icon_name_);
}

void IconSelectorDialog::set_icon_name(const Glib::ustring &name) {
  selector_.set_icon_name(name);
}
Glib::ustring IconSelectorDialog::get_icon_name() {
  return selector_.get_icon_name();
}

IconSelectorDialog::IconSelectorDialog(Gtk::Window         &parent,
                                       const Glib::ustring &icon_name) :
  Gtk::Dialog   (_("Icon selector"), parent),
  icon_name_    (icon_name),
  selector_     (*this),
  add_button_   (Gtk::Stock::ADD),
  remove_button_(Gtk::Stock::REMOVE)
{
  add_button_.signal_clicked()
    .connect(sigc::mem_fun(selector_, &IconSelector::add));
  remove_button_.signal_clicked()
    .connect(sigc::mem_fun(selector_, &IconSelector::add));

  get_vbox()->pack_start(selector_);
  get_action_area()->pack_start(add_button_);
  get_action_area()->pack_start(remove_button_);
  add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
  add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
  show_all();
  resize(480, 320);
}

//========================
// CellRendererIcon
void CellRendererIcon::dialog_on_response(int response_id) {
  if (response_id == Gtk::RESPONSE_OK) {
    signal_edited_(editing_path_, dialog_->get_icon_name());
  }
}

bool CellRendererIcon::activate_vfunc(GdkEvent              */*event*/,
                                      Gtk::Widget           &/*widget*/,
                                      const Glib::ustring   &path,
                                      const Gdk::Rectangle  &/*background_area*/,
                                      const Gdk::Rectangle  &/*cell_area*/,
                                      Gtk::CellRendererState /*flags*/) {
  editing_path_ = path;
  if (!dialog_) dialog_.reset(new IconSelectorDialog(parent_));
  dialog_->set_icon_name(icon_name_);
  dialog_->show();
  return false;
}

void CellRendererIcon::set_icon_name(const Glib::ustring &name) {
  icon_name_ = name;
  property_pixbuf() = IconManager::load_icon(name, IconManager::ICON_SIZE_16);
}

CellRendererIcon::CellRendererIcon(Gtk::Window &parent) :
  parent_(parent)
{
  property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE;
  dialog_.signal_response().connect(sigc::mem_fun(*this, &CellRendererIcon::dialog_on_response));
}

}/*pref*/
}/*gpyp*/
